#include "StdAfx.h"

namespace ui 
{
	DragDropManager::~DragDropManager()
	{
		if (m_pDragMoveWindow)
			m_pDragMoveWindow->Close();
	};

	bool DragDropManager::IsDraging(const Window *pWindow)
	{
		return m_pDragControl && m_pDragWindow && m_pDragWindow == pWindow;
	}

	bool DragDropManager::StartDrag(const Control* pDragControl, CPoint pt, Window *pWindow)
	{
		printf("DragDropManager::StartDrag\n");
		assert(pWindow);
		assert(!m_pDragControl);
		if (m_pDragControl)
			StopDrag();
		//pDragControl->SetAlpha(0);
		m_rcStart = pDragControl->GetPosWithScrollOffset();
		m_nIndexStart = pDragControl->GetIndex();
		m_pDragControl = pDragControl;
		m_ptStart = pt;
		m_ptMove = pt;
		m_pDragWindow = pWindow;

		if (!m_pDragMoveWindow)
		{
			m_pDragMoveWindow = new DragMoveWindow();
			m_pDragMoveWindow->Create(NULL, m_pDragMoveWindow->GetWindowClassName().c_str(), WS_POPUP, WS_EX_NOACTIVATE, false);	
		}

		UiRect rcPos = pDragControl->GetPos();
		m_pDragMoveWindow->StartDrag(pDragControl, pWindow);

		if (pDragControl->GetParent())
			pDragControl->GetParent()->StartDragChild((Control*)pDragControl, pt);
		pWindow->StartDragControl((Control*)pDragControl, pt);
		return true;
	}

	bool DragDropManager::UpdateDrag(const Control* pDragControl, CPoint pt, Window *pWindow)
	{
		assert(pDragControl == m_pDragControl);
		if (!m_pDragControl || pDragControl != m_pDragControl)
			StopDrag();

		UiRect rcPos = m_pDragControl->GetPosWithScrollOffset();
		m_ptStart.x += rcPos.left - m_rcStart.left;
		m_ptStart.y += rcPos.top - m_rcStart.top;
		m_rcStart = rcPos;
		if (pWindow && pWindow != m_pDragWindow)
			m_pDragWindow = pWindow;
		return true;
	}

	void DragDropManager::MoveDrag(const Control* pDragControl, CPoint pt)
	{
		assert(m_pDragControl && pDragControl == m_pDragControl);
		if (pDragControl != m_pDragControl)
		{
			StopDrag();
			return;
		}

		//printf("DragDropManager::MoveDrag %d, %d\n", pt.x, pt.y);
		m_ptMove = pt;	

		int ptOffx = m_ptMove.x - m_ptStart.x;
		int ptOffy = m_ptMove.y - m_ptStart.y;

		if (m_pDragMoveWindow)
		{
			UiRect rcPos = m_pDragMoveWindow->GetStartPos();
			rcPos.Offset({ ptOffx, ptOffy });
			m_pDragMoveWindow->SetPos(rcPos, true, SWP_NOACTIVATE | SWP_NOSIZE);
		}
	}

	bool DragDropManager::StopDrag()
	{
		if (!m_pDragControl || !m_pDragWindow)
			return true;
		printf("DragDropManager::StopDrag\n");
		if (m_pDragControl->GetParent())
			m_pDragControl->GetParent()->StopDragChild();
		m_pDragWindow->StopDragControl((Control*)m_pDragControl);

		if (m_pDragMoveWindow)
			m_pDragMoveWindow->StopDrag();

		m_pDragControl = nullptr;
		m_pDragWindow = nullptr;
		m_ptStart = CPoint(-1. - 1);
		m_ptMove = CPoint(-1. - 1);
	
		return true;
	}

	//void DragDropManager::PaintDragControl(IRenderContext* pRender, const UiRect& rcPaint)
	//{
	//	HDC hdc = pRender->GetDC();
	//	UiRect rcControl = m_pDragControl->GetPosWithScrollOffset();
	//	//m_pDragControl->GetPosWithScrollOffset();

	//	int left = rcControl.left;
	//	int top = rcControl.top;
	//	int controlWidth = rcControl.GetWidth();
	//	int controlHeight = rcControl.GetHeight();

	//	int ptOffx = m_ptMove.x - m_ptStart.x;
	//	int ptOffy = m_ptMove.y - m_ptStart.y;

	//	HDC hMemDC = CreateCompatibleDC(hdc);
	//	HBITMAP hbmp = CreateCompatibleBitmap(hdc, controlWidth, controlHeight);
	//	HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemDC, hbmp);
	//	::BitBlt(hMemDC, 0, 0, controlWidth, controlHeight, hdc, left, top, SRCCOPY);
	//	::BitBlt(hdc, left + ptOffx, top + ptOffy, controlWidth, controlHeight, hMemDC, 0, 0, SRCAND);
	//	hbmp = (HBITMAP)SelectObject(hMemDC, hOldBitmap);
	//	DeleteDC(hMemDC);
	//	//::ReleaseDC(NULL, hdc);
	//	DeleteObject(hbmp);
	//}

	/********************************************DragMoveWindow*********************************************/
	/********************************************DragMoveWindow*********************************************/
	DragMoveWindow::DragMoveWindow() 
	{

	}

	DragMoveWindow::~DragMoveWindow()
	{

	}

	std::wstring DragMoveWindow::GetSkinFolder()
	{
		return L"public/dragdrop";
	}

	std::wstring DragMoveWindow::GetSkinFile()
	{
		return L"drag_move_window.xml";
	}

	std::wstring DragMoveWindow::GetWindowClassName() const
	{
		return L"DragMoveWindow";
	}

	void DragMoveWindow::InitWindow()
	{
		m_pRoot->SetAutoDestroyChild(false);
	}

	LRESULT DragMoveWindow::OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		return 0;
	}

	bool DragMoveWindow::StartDrag(const Control* pDragControl, Window *pWindow)
	{
		std::wstring sBkImage = CreateBkImage(pDragControl, pWindow);
		m_pRoot->SetBkImage(sBkImage);
		
		UiRect rcPos = pDragControl->GetPosWithScrollOffset();
		rcPos = pWindow->MapDesktopRect(rcPos);
		SetPos(rcPos, true, SWP_NOACTIVATE | SWP_SHOWWINDOW);

		m_pDragControl = pDragControl;
		m_rcPos = rcPos;	
		return true;
	}
	bool DragMoveWindow::StopDrag()
	{
		m_pDragControl = nullptr;
		m_rcPos = UiRect();
		ShowWindow(false);
		return true;
	}

	std::wstring DragMoveWindow::CreateBkImage(const Control* pDragControl, Window *pWindow)
	{
		CLSID clsid;
		if (!ImageUtil::GetImageCLSID(L"image/png", &clsid))
			return L"";

		HDC hdc = pWindow->GetRenderContext()->GetDC();
		UiRect rcControl = pDragControl->GetPosWithScrollOffset();

		int left = rcControl.left;
		int top = rcControl.top;
		int controlWidth = rcControl.GetWidth();
		int controlHeight = rcControl.GetHeight();

		HDC hMemDC = CreateCompatibleDC(hdc);
		HBITMAP hbmp = CreateCompatibleBitmap(hdc, controlWidth, controlHeight);
		HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemDC, hbmp);
		::BitBlt(hMemDC, 0, 0, controlWidth, controlHeight, hdc, left, top, SRCCOPY);
		(HBITMAP)SelectObject(hMemDC, hOldBitmap);

		std::wstring sFilePath = PathUtil::GetCurrentModuleDir() + L"drag_control.png";
		Gdiplus::Bitmap bmp(hbmp, NULL);
		int quality_num = 95;
		Gdiplus::EncoderParameters encoder_paramters;
		encoder_paramters.Count = 1;
		encoder_paramters.Parameter[0].Guid = Gdiplus::EncoderQuality;
		encoder_paramters.Parameter[0].NumberOfValues = 1;
		encoder_paramters.Parameter[0].Type = Gdiplus::EncoderParameterValueTypeLong;
		encoder_paramters.Parameter[0].Value = (void*)&quality_num;
		if (bmp.Save(sFilePath.c_str(), &clsid, &encoder_paramters) != Gdiplus::Status::Ok)
		{
			sFilePath = L"";
		}

		DeleteDC(hMemDC);
		DeleteObject(hbmp);

		return sFilePath;
	}
};

